/**
 * 
 */
package cn.springsoter.core.security.interceptor;

import java.lang.reflect.Field;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.Objects;

import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.ibatis.executor.resultset.ResultSetHandler;
import org.apache.ibatis.plugin.Interceptor;
import org.apache.ibatis.plugin.Intercepts;
import org.apache.ibatis.plugin.Invocation;
import org.apache.ibatis.plugin.Signature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import cn.hutool.core.util.CharsetUtil;
import cn.springsoter.core.security.helper.CryptoHelper;
import cn.springsoter.core.security.strategy.impl.ReadAESKeyDefaultStrategy;
import cn.springsoter.core.security.strategy.impl.ReadAESKeyStoreStrategy;
import cn.springsoter.core.tool.utils.AESUtil;
import lombok.extern.slf4j.Slf4j;

/**
 * Mybatis拦截器：解密拦截器，出库后解密，只支持String类型的字段
 * 
 * @author kevin
 *
 */
@Slf4j
@Component
@Intercepts({
		/*
		 * // 语句执行拦截
		 * Executor (update, query, flushStatements, commit, rollback, getTransaction, 
		 * close, isClosed) 
		 * // 参数获取、设置时进行拦截
		 * ParameterHandler (getParameterObject, setParameters) 
		 * // 对返回结果进行拦截
		 * ResultSetHandler (handleResultSets, handleOutputParameters) 
		 * // sql语句拦截
		 * StatementHandler (prepare, parameterize, batch, update, query)
		 */
		@Signature(type = ResultSetHandler.class, method = "handleResultSets", args = { Statement.class }) })
public class DecryptInterceptor implements Interceptor {
	
	@Autowired
	private ReadAESKeyDefaultStrategy readAESKeyDefaultStrategy;
	@Autowired
	private ReadAESKeyStoreStrategy readAESKeyStoreStrategy;
	
	@Override
	public Object intercept(Invocation invocation) throws Throwable {
		// 取出查询的结果
		Object resultObject = invocation.proceed();//这一步会调用对应的TypeHandler
		if (Objects.isNull(resultObject)) {
			return null;
		}
		// 基于selectList
		if (resultObject instanceof ArrayList) {
			ArrayList resultList = (ArrayList) resultObject;
			if (CollectionUtils.isNotEmpty(resultList)) {
				for (Object result : resultList) {
					// 判空
					if(Objects.nonNull(result)) {
						// 逐一解密
						decrypt(result);
					}
				}
			}
		} else {// 基于selectOne
			decrypt(resultObject);
		}
		return resultObject;
	}

	
	/**
	 * 解密
	 * 
	 * @param result	查询返回结果
	 * @throws IllegalArgumentException
	 * @throws IllegalAccessException
	 */
	private void decrypt(Object result) throws Exception {
		// 取出resultType的类
		Class<?> resultClass = result.getClass();
		Field[] declaredFields = resultClass.getDeclaredFields();
		for (Field field : declaredFields) {
			// 校验该字段是否被@SensitiveInfo所注解，并且设置needCrypto=true
			if (CryptoHelper.needCrypto(field)) {
				field.setAccessible(true);
				Object object = field.get(result);
				// 只支持String的解密
				if (object instanceof String) {
					String value = (String) object;
					log.debug("======mybatis拦截器（DecryptInterceptor）执行中，拦截的字段名是：{}，值是：{}", field.getName(), value);

					if (StringUtils.isNotBlank(value)) {
						String key = StringUtils.isBlank(readAESKeyStoreStrategy.readKey()) ? readAESKeyDefaultStrategy.readKey() : readAESKeyStoreStrategy.readKey();
						if(StringUtils.isNotBlank(key)) {
							try {
								value = AESUtil.decryptByECBString(key.getBytes(CharsetUtil.CHARSET_UTF_8), value);
							} catch (Exception e) {}
						}
					}
					field.set(result, value);
				}
			}
		}
	}
}
